/*
 * @Author: Shiire
 * @Date: 2022-07-22 22:21:03
 * @LastEditors: Shiire
 * @LastEditTime: 2022-07-24 18:52:47
 * @Description: 封装上传文件的方法
 * @FilePath: \grapro\src\upload.js
 */
import createClient from "@/alicloud.js";
import axios from '@/utils/instance.js';
import SparkMD5 from "spark-md5";

const bucket = 'bucket-nobo';
const region = 'oss-cn-shenzhen'

/**
 * @description: 1、简单上传文件
 * @return {*}
 */

export const putObject = async (file, directory = 'uploads') => {
    if (!file) {
        return
    }

    try {
        const client = await createClientFn()

        const { buffer, HASH, suffix, filename } = await changeBuffer(file);

        const result = await client.put(`${directory}/${filename}`, file);

        return result
    } catch (error) {
        console.log(error)
    }
}

/**
 * @description: 2、断点续传上传文件
 * @return {*}
 */

export const continuinglyTransferring = async (file, directory = 'uploads', onProgress = () => { }) => {
    if (!file) {
        return
    }

    const client = await createClientFn()

    const { buffer, HASH, suffix, filename } = await changeBuffer(file);

    // 判断是否上传该文件到OSS了，是的话直接返回文件地址
    const isExistUploadfile = await isExistObject(`${directory}/${filename}`, client)

    if (isExistUploadfile) {
        onProgress(100)

        return {
            url: `https://${bucket}.${region}.aliyuncs.com/${directory}/${filename}`
        }
    }

    // 定义中断点。
    let abortCheckpoint

    // 判断是否存在已上传的切片
    const isExistAbortCheckpoint = await isExistObject(`${directory}/${HASH}.json`, client)

    if (isExistAbortCheckpoint) {
        try {
            const result = await client.get(`${directory}/${HASH}.json`);
            abortCheckpoint = JSON.parse(result.content.toString())
        } catch (e) {
            console.log(e);
        }
    }

    const options = {
        // 获取分片上传进度、断点和返回值。
        progress: async (p, cpt, res) => {
            let progress = parseInt(p * 100)

            onProgress(progress)

            abortCheckpoint = cpt

            // 上成保存中断点的文件
            const jsonFile = await createJSONFile(abortCheckpoint)

            await client.put(`${directory}/${HASH}.json`, jsonFile)
        },

        checkpoint: abortCheckpoint,
        // 设置并发上传的分片数量。
        parallel: 4,
        // 设置分片大小。默认值为1 MB，最小值为100 KB。
        partSize: 1024 * 1024,
        // headers,
        // 自定义元数据，通过HeadObject接口可以获取Object的元数据。
        meta: { year: 2020, people: "test" },
        mime: "text/plain",
    };

    try {
        return await client.multipartUpload(`${directory}/${filename}`, file, {
            ...options
        }).then(async (response) => {
            response.url = `https://${bucket}.${region}.aliyuncs.com/${response.name}`

            // 上传完毕，删除保存中断点的JSON文件
            await client.delete(`${directory}/${HASH}.json`);

            return response
        })

    } catch (error) {
        console.log(error)
    }

}

/**
 * @description: 将文件进行解析
 * @params {file} file
 * @return {object} {buffer,HASH,suffix,filename}
 */

const changeBuffer = async (file) => {
    return new Promise((resolve) => {
        let fileReader = new FileReader();
        fileReader.readAsArrayBuffer(file);
        fileReader.onload = (ev) => {
            let buffer = ev.target.result,
                spark = new SparkMD5.ArrayBuffer(),
                HASH,
                suffix;
            spark.append(buffer);
            HASH = spark.end();
            suffix = /\.([a-zA-Z0-9]+)$/.exec(file.name)[1];
            resolve({
                buffer,
                HASH,
                suffix,
                filename: `${HASH}.${suffix}`,
            });
        };
    });
};

const createClientFn = async () => {
    const result = await axios.get("/getSecurityToken").then(async (response) => {
        const client = await createClient(response.data.credentials);
        return client
    }).catch(err => err);

    return result
}

/**
 * @description: 生成JSON文件
 * @return {*}
 */

const createJSONFile = async (data) => {
    if (typeof data === 'object') {
        data = JSON.stringify(data)
    }

    const blob = new Blob([data], { type: 'text/json' })
    return blob
}

/**
 * @description: 判断OSS中文件是否存在
 * @return {*}
 */

const isExistObject = async (name, client, options = {}) => {
    try {
        await client.head(name, options);
        return true
    } catch (error) {
        if (error.code === 'NoSuchKey') {
            return false
        }
    }
}